using System;
using System.Collections;
using System.Diagnostics;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;

using Pegasus.Diagnostics;

namespace Pegasus.Collections
{
	/// <summary>
	/// Extends the <see cref="Hashtable"/> and adds the ability to save and load the table
	/// from a stream.
	/// </summary>
	/// <remarks>
	///		<p>
	///		The StreamHashtable can only contain keys and objects that can be serialized.
	///		If the Save() method is call and the table contains a key or an object that is not 
	///		marked as serializable an exception will be thrown.
	///		</p>
	///		<p>
	///		See <see cref="SerializableAttribute"/> attribute or the <see cref="ISerializable"/> 
	///		interface for information about serializable objects.
	///		</p>
	/// </remarks>
	/// <example>
	///		<p>
	///		The following example show how to create a StreamHashtable, Save it, and reload it.
	///		</p>
	///		<code>
	///		public void SaveTable( Stream myStream )
	///		{
	///			FileHashtable table = new FileHashtable( myStream );
	///			
	///			table[ "red" ] = Color.Red;
	///			table[ "blue" ] = Color.Blue;
	///			table[ "yellow" ] = Color.Yellow;
	///			
	///			table.Save();
	///			table.Close();
	///		}
	///		
	///		public void LoadTable( Stream myStream )
	///		{
	///			FileHashtable table = new FileHashtable( myStream );
	///			
	///			Color red = table[ "red" ];
	///			Color blue = table[ "blue" ];
	///			Color yellow = table[ "yellow" ];
	/// 
	///			table.Close();
	///		}
	///		</code>
	/// </example>
	[Obsolete( "Use the Generic class Pegasus.Collections.Generic.DictionaryAppData", false )]
	[Serializable]
	public class StreamHashtable : Hashtable, IDisposable
	{
		// Local Instance Values
		[NonSerialized]
		private Stream m_stream = null;

		[NonSerialized]
		private IFormatter m_formatter = new BinaryFormatter();

		/// <summary>
		/// 
		/// </summary>
		protected StreamHashtable( SerializationInfo info, StreamingContext context ) :
			base( info, context )
		{
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="stream"></param>
		public StreamHashtable( Stream stream )
		{
			ParamCode.AssertNotNull( stream, "stream" );
			ParamCode.Assert( stream.CanRead && stream.CanWrite && stream.CanSeek, "stream must suport read, write, and seek capibilities" );

			m_stream = stream;
			
			Load();
		}

		/// <summary>
		/// 
		/// </summary>
		protected Stream Stream
		{
			get
			{
				return m_stream;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public void Dispose()
		{
			Close();
		}

		/// <summary>
		/// 
		/// </summary>
		public virtual void Save()
		{
			if( m_stream != null )
			{
				m_stream.SetLength( 0 );
				m_formatter.Serialize( m_stream, this );
				
				m_stream.Flush();
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public virtual void Close()
		{
			if( m_stream != null )
			{
				m_stream.Close();
				m_stream = null;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public virtual void Load()
		{
			if( m_stream != null && m_stream.Length > 0 )
			{
				m_stream.Seek( 0, SeekOrigin.Begin );
				Hashtable newTable = (Hashtable) m_formatter.Deserialize( m_stream );

				// Clear any current contents of this table
				Clear();

				// Copy element into this table
				foreach( DictionaryEntry entry in newTable )
				{
					Add( entry.Key, entry.Value );
				}
			}
		}
	}
}
